package org.joy.config;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.joy.config.model.DatabaseElement;
import org.joy.config.model.TemplateElement;
import org.joy.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Configuration {

	private static final String CONFIGURATION_FILE = "configuration.xml";
	private String configurationFile;
	private String tagertProject;
	private String basePackage;
	private List<TemplateElement> templates;
	private List<DatabaseElement> dataBases;

	public Configuration(String classPath) {
		this.configurationFile = classPath + CONFIGURATION_FILE;
		templates = new ArrayList<TemplateElement>();
	}

	public void loadConfiguration()
			throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = factory.newDocumentBuilder();
		Document doc = docBuilder.parse(configurationFile);

		XPathFactory f = XPathFactory.newInstance();
		XPath path = f.newXPath();

		parseConnections(doc, path);
		parseTemplates(doc, path);

		tagertProject = path.evaluate("/configuration/tagertProject/text()", doc);
		basePackage = path.evaluate("/configuration/basePackage/text()", doc);
	}

	private void parseConnections(Document doc, XPath path) throws XPathExpressionException {
		NodeList databaseList = (NodeList) path.evaluate("configuration/connections/database", doc,
				XPathConstants.NODESET);
		if (databaseList != null) {
			for (int i = 0; i < databaseList.getLength(); i++) {
				parseDatabase(databaseList.item(i), path);
			}
		}
	}

	private void parseDatabase(Node node, XPath path) throws XPathExpressionException {
		String name = path.evaluate("@name", node);
		String driverClass = path.evaluate("./driverClass/text()", node);
		String url = path.evaluate("./url/text()", node);
		String username = path.evaluate("./username/text()", node);
		String password = path.evaluate("./password/text()", node);
		String schema = path.evaluate("./schema/text()", node);

		if (StringUtil.isNotEmpty(name) && StringUtil.isNotEmpty(driverClass) && StringUtil.isNotEmpty(url)
				&& StringUtil.isNotEmpty(username)) {
			dataBases.add(new DatabaseElement(name, driverClass, url, username, password, schema));
		}
	}

	private void parseTemplates(Document doc, XPath path) throws XPathExpressionException {
		NodeList templateList = (NodeList) path.evaluate("configuration/templates/template", doc,
				XPathConstants.NODESET);
		if (templateList != null) {
			for (int i = 0; i < templateList.getLength(); i++) {
				parseTemplate(templateList.item(i), path);
			}
		}
	}

	private void parseTemplate(Node node, XPath path) throws XPathExpressionException {
		String name = null, engine = null, templateFile = null, targetPath = null, targetFileName = null,
				encoding = null;
		templateFile = path.evaluate("./templateFile/text()", node);
		targetPath = path.evaluate("./targetPath/text()", node);
		targetFileName = path.evaluate("./targetFileName/text()", node);
		encoding = path.evaluate("./encoding/text()", node);

		name = path.evaluate("@name", node);
		engine = path.evaluate("@engine", node);

		if (StringUtil.isEmpty(engine)) {
			engine = "freemarker";
		}
		if (StringUtil.isEmpty(encoding)) {
			encoding = "UTF-8";
		}
		if (StringUtil.isEmpty(name)) {
			name = templateFile;
		}
		if (StringUtil.isNotEmpty(templateFile) && StringUtil.isNotEmpty(targetPath)
				&& StringUtil.isNotEmpty(targetFileName)) {
			TemplateElement templateElement = new TemplateElement(name, engine, templateFile, targetPath,
					targetFileName, encoding);
			templates.add(templateElement);
			templateElement.setSelected(Boolean.parseBoolean(parseAttributes(node).getProperty("selected")));
		}
	}

	private Properties parseAttributes(Node node) {
		Properties attributes = new Properties();
		NamedNodeMap nnm = node.getAttributes();
		for (int i = 0; i < nnm.getLength(); i++) {
			Node attribute = nnm.item(i);
			String value = attribute.getNodeValue();
			attributes.put(attribute.getNodeName(), value);
		}

		return attributes;
	}

	public List<DatabaseElement> getDatabases() {
		return dataBases;
	}

	public String getTagertProject() {
		return tagertProject;
	}

	public void setTagertProject(String tagertProject) {
		this.tagertProject = tagertProject;
	}

	public String getBasePackage() {
		return basePackage;
	}

	public void setBasePackage(String basePackage) {
		this.basePackage = basePackage;
	}

	public List<TemplateElement> getTemplates() {
		return templates;
	}
}
